#include "app_pool.h"
#include "log/log.h"
#include "app_pool.h"
#include <stdlib.h>
#include <mqueue.h>

static pthread_t *thread_pool;  // 线程池容器
static int thread_num;           // 线程池中线程数量
static char *mq_name = "/gateway_mq"; // 消息队列名字
static mqd_t mq_fd;                 // 消息队列的文件描述符

//创建线程池的线程函数 ：从消息队列中获取任务并执行
//当线程池中的线程被创建时，它们会执行这个函数。当接受到消息队列任务时，线程会执行任务函数。
void *thread_func(void *arg)
{
    app_task_t task;
    while (1)
    {
        // 从消息队列中接收任务
        //为什么存储在task中？
        /*task 是一个已经声明和初始化的结构体变量，它是接收任务数据的容器。
        这个变量的类型是 app_task_t，意味着它的结构与任务的数据格式相匹配。
        《《通过 mq_receive 函数，我们将消息队列中的数据直接存储到这个结构体中》》。*/
        ssize_t len = mq_receive(mq_fd, (char*)&task, sizeof(app_task_t), NULL); // 从消息队列中接收消息
        //如果接收到的任务大小与预期相同（即 sizeof(app_task_t)），则执行任务
        //sizeof 运算符用于返回一个数据类型（例如类型、变量、结构体等）占用的内存空间的大小（以字节为单位）。
       //得到结构体 Task 所占的内存大小，这个大小包含了所有成员的内存加上可能的内存填充（为了保证内存对齐）。
        if(len==sizeof(app_task_t))
        {
            task.task_func(task.arg); // 执行任务
        }
    }

}

/**
 * @brief 初始化任务池，创建指定数量的线程。
 *
 * @param thread_num 线程池中线程的数量。
 * @return int 初始化成功返回0，失败返回负数。
 */
int app_pool_init(int num)
{
    //创建多个线程 并添加到线程池中
    thread_num=num;
    thread_pool = malloc(sizeof(pthread_t) * thread_num);
    for (size_t i = 0; i < num; i++)
    {
        pthread_create(&thread_pool[i], NULL, thread_func, NULL);
    }
    //创建消息队列
    struct mq_attr attr;
    attr.mq_maxmsg = 10; // 消息队列中最大消息数
    //sizeof 运算符用于返回一个数据类型（例如类型、变量、结构体等）占用的内存空间的大小（以字节为单位）。
    //得到结构体 Task 所占的内存大小，这个大小包含了所有成员的内存加上可能的内存填充（为了保证内存对齐）。
    attr.mq_msgsize = sizeof(app_task_t); // 消息队列中每个消息的最大字节数
    mq_fd =mq_open(mq_name, O_CREAT | O_RDWR, 0666, &attr); // 创建消息队列
    return 0;
}

/**
 * @brief 销毁任务池，释放资源并停止所有线程。
 *         删除所有线程 消息队列
 *
 * 该函数会等待所有线程完成当前任务后退出，释放分配的资源。
 */
void app_pool_destroy()
{
    for (size_t i = 0; i < thread_num; i++)
    {
        /* code */
        pthread_cancel(thread_pool[i]);// 取消指定的线程
        pthread_join(thread_pool[i], NULL);// 等待指定线程的结束
    }
        // 释放线程池容器
        free(thread_pool);
        // 关闭删除消息队列
        mq_close(mq_fd);
        mq_unlink(mq_name);
}
/**
 * @brief 向任务池中注册一个任务。
 *
 * 将任务函数和任务参数添加到任务池中，任务池将调度线程来执行该任务。
 * 
 * @param task_func 任务函数，指向任务的执行函数。
 * @param arg 任务的参数，可以是任意类型的数据。
 * @return int 注册成功返回0，失败返回负数。
 */
int app_pool_registerTask(int (*task_func)(void *arg), void *arg)
{ 
    //创建任务
    app_task_t task;
    task.task_func=task_func;
    task.arg=arg;
    //将创建的任务结构体数据（函数，函数参数）发送到消息队列中
    mq_send(mq_fd, (char*)&task, sizeof(app_task_t), 0);
}